﻿using Ln.Fram.Ddd.Application.Contracts;
using Ln.Fram.SqlSugarCore.Abstractions;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using SqlSugar;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;

namespace Ln.Fram.Ddd.Application;

/*
public abstract class
	LnCrudAppService<TEntity, TEntityDto, TKey> : LnCrudAppService<TEntity, TEntityDto, TKey,
	PagedAndSortedResultRequestDto>
	where TEntity : class, IEntity<TKey>, new()
	where TEntityDto : IEntityDto<TKey>
{
	protected LnCrudAppService(ISqlSugarRepository<TEntity, TKey> repository) : base(repository)
	{
	}
}

public abstract class
	LnCrudAppService<TEntity, TEntityDto, TKey, TGetListInput> : LnCrudAppService<TEntity, TEntityDto, TKey, TGetListInput
	, TEntityDto>
	where TEntity : class, IEntity<TKey>, new()
	where TEntityDto : IEntityDto<TKey>
{
	protected LnCrudAppService(ISqlSugarRepository<TEntity, TKey> repository) : base(repository)
	{
	}
}

public abstract class
	LnCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput> : LnCrudAppService<TEntity, TEntityDto, TKey,
	TGetListInput, TCreateInput, TCreateInput>
	where TEntity : class, IEntity<TKey>, new()
	where TEntityDto : IEntityDto<TKey>
{
	protected LnCrudAppService(ISqlSugarRepository<TEntity, TKey> repository) : base(repository)
	{
	}
}

public abstract class LnCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput> :
	LnCrudAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
	where TEntity : class, IEntity<TKey>, new()
	where TEntityDto : IEntityDto<TKey>
{
	protected LnCrudAppService(ISqlSugarRepository<TEntity, TKey> repository) : base(repository)
	{
	}
}

public abstract class LnCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput,
	TUpdateInput>
	: CrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
	where TEntity : class, IEntity<TKey>, new()
	where TGetOutputDto : IEntityDto<TKey>
	where TGetListOutputDto : IEntityDto<TKey>
{
	protected new ISqlSugarRepository<TEntity, TKey> Repository { get; }

	protected LnCrudAppService(ISqlSugarRepository<TEntity, TKey> repository) : base(repository)
	{
		Repository = repository;
	}

	public override async Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input)
	{
		await CheckUpdatePolicyAsync();
		var entity = await GetEntityByIdAsync(id);
		await CheckUpdateInputDtoAsync(entity, input);
		await MapToEntityAsync(input, entity);
		await Repository.UpdateAsync(entity, autoSave: true);
		return await MapToGetOutputDtoAsync(entity);
	}

	protected virtual Task CheckUpdateInputDtoAsync(TEntity entity, TUpdateInput input)
	{
		return Task.CompletedTask;
	}

	public override async Task<TGetOutputDto> CreateAsync(TCreateInput input)
	{
		await CheckCreatePolicyAsync();
		await CheckCreateInputDtoAsync(input);
		var entity = await MapToEntityAsync(input);
		TryToSetTenantId(entity);
		await Repository.InsertAsync(entity, autoSave: true);
		return await MapToGetOutputDtoAsync(entity);
	}

	protected virtual Task CheckCreateInputDtoAsync(TCreateInput input)
	{
		return Task.CompletedTask;
	}

	/// <summary>
	/// 多查
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	public override async Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
	{
		List<TEntity>? entities = null;
		RefAsync<int> totalCount = 0;
		await CheckGetListPolicyAsync();
		var queryable = CreateFilterQueryable(input);
		if (input is IPagedResultRequest pagedInput)
		{
			entities = await queryable.ToOffsetPageAsync(pagedInput.SkipCount, pagedInput.MaxResultCount, totalCount);
		}
		else
		{
			entities = await queryable.ToListAsync();
			totalCount = entities.Count;
		}
		return new PagedResultDto<TGetListOutputDto>(totalCount, await MapToGetListOutputDtosAsync(entities));
	}

	protected virtual ISugarQueryable<TEntity> CreateFilterQueryable(TGetListInput input)
	{
		var queryable = Repository._DbQueryable;
		if (input is IPagedAllResultRequestDto allInput && typeof(TEntity).IsAssignableTo(typeof(IHasCreationTime)))
			queryable.WhereIF(allInput.StartTime is not null, x => (x as IHasCreationTime).CreationTime >= allInput.StartTime)
				.WhereIF(allInput.EndTime is not null,
					x => (x as IHasCreationTime).CreationTime <= allInput.EndTime.Value.AddDays(1));
		return queryable;
	}

	/// <summary>
	/// 多删
	/// </summary>
	/// <param name="id"></param>
	/// <returns></returns>
	[RemoteService(isEnabled: true)]
	public virtual async Task DeleteAsync(IEnumerable<TKey> id)
	{
		await Repository.DeleteManyAsync(id);
	}

	/// <summary>
	/// 偷梁换柱
	/// </summary>
	/// <param name="id"></param>
	/// <returns></returns>
	[RemoteService(isEnabled: false)]
	public override Task DeleteAsync(TKey id)
	{
		return base.DeleteAsync(id);
	}

	/// <summary>
	/// 导出excel
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	public virtual async Task<IActionResult> GetExportExcelAsync(TGetListInput input)
	{
		if (input is IPagedResultRequest paged)
		{
			paged.SkipCount = 0;
			paged.MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount;
		}
		var output = await this.GetListAsync(input);
		var dirPath = $"/wwwroot/temp";
		var fileName = $"{typeof(TEntity).Name}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}_{Guid.NewGuid()}";
		var filePath = $"{dirPath}/{fileName}.xlsx";
		if (!Directory.Exists(dirPath))
		{
			Directory.CreateDirectory(dirPath);
		}
		MiniExcel.SaveAs(filePath, output.Items);
		return new PhysicalFileResult(filePath, "application/vnd.ms-excel");
	}

	/// <summary>
	/// 导入excle
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	public virtual async Task PostImportExcelAsync(List<TCreateInput> input)
	{
		var entities = input.Select(x => MapToEntity(x)).ToList();
		//安全起见，该接口需要自己实现

		throw new NotImplementedException();
		//await Repository.DeleteManyAsync(entities.Select(x => x.Id));
		//await Repository.InsertManyAsync(entities);
	}
}*/